// ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
//==========================================================================
//  File:       IpcHandler.cs 
//  Author:   [....]@Microsoft.com 
//  Summary:    Class for managing a socket connection.
// 
//=========================================================================

using System;
using System.IO; 
using System.Runtime.Remoting.Messaging;
using System.Runtime.InteropServices; 
using System.Text; 
using System.Threading;
using System.Runtime.Remoting.Channels.Tcp; 
using System.Globalization;


namespace System.Runtime.Remoting.Channels.Ipc 
{
 
    internal class IpcServerHandler : TcpSocketHandler 
    {
        // The stream to manage incoming request data 
        private Stream _stream = null;
        protected Stream _requestStream = null;
        // NamePipe associated with this manager
        protected IpcPort _port; 
        private RequestQueue _requestQueue;
        bool _bOneWayRequest; 
        int _contentLength; 

        internal IpcServerHandler(IpcPort port, RequestQueue requestQueue, Stream stream) : base (null, requestQueue, stream) 
        {
            _requestQueue = requestQueue;
            _port = port;
            _stream = stream; 
        }
 
        internal Stream GetRequestStream() 
        {
                _requestStream =  new TcpFixedLengthReadingStream(this, _contentLength); 
                return _requestStream;
        }

        internal IpcPort Port { 
            get {
                return _port; 
            } 
        }
 
        internal ITransportHeaders ReadHeaders()
        {
            BaseTransportHeaders headers = new BaseTransportHeaders();
 
            UInt16 operation;
            ReadVersionAndOperation(out operation); 
 
            if (operation == TcpOperations.OneWayRequest)
            { 
                _bOneWayRequest = true;
            }

            bool bChunked = false; 
            // content length must come next (may be chunked or a specific length)
            ReadContentLength(out bChunked, out _contentLength); 
 
            // read to end of headers
            ReadToEndOfHeaders(headers); 

            return headers;
        }
 
        protected new void ReadToEndOfHeaders(BaseTransportHeaders headers)
        { 
            bool bError = false; 
            String statusPhrase = null;
 
            UInt16 headerType = ReadUInt16();
            while (headerType != TcpHeaders.EndOfHeaders)
            {
                if (headerType == TcpHeaders.Custom) 
                {
                    String headerName = ReadCountedString(); 
                    String headerValue = ReadCountedString(); 

                    headers[headerName] = headerValue; 
                }
                else
                if (headerType == TcpHeaders.RequestUri)
                { 
                    ReadAndVerifyHeaderFormat("RequestUri", TcpHeaderFormat.CountedString);
 
                    // read uri (and make sure that no channel specific data is present) 
                    String uri = ReadCountedString();
 
                    String channelURI;
                    String objectURI;
                    channelURI = IpcChannelHelper.ParseURL(uri, out objectURI);
                    if (channelURI == null) 
                        objectURI = uri;
 
                    headers.RequestUri = objectURI; 
                }
                else 
                if (headerType == TcpHeaders.StatusCode)
                {
                    ReadAndVerifyHeaderFormat("StatusCode", TcpHeaderFormat.UInt16);
 
                    UInt16 statusCode = ReadUInt16();
                    // We'll throw an exception here if there was an error. If an error 
                    //   occurs above the transport level, the status code will still be 
                    //   success here.
                    if (statusCode != TcpStatusCode.Success) 
                        bError = true;
                }
                else
                if (headerType == TcpHeaders.StatusPhrase) 
                {
                    ReadAndVerifyHeaderFormat("StatusPhrase", TcpHeaderFormat.CountedString); 
 
                    statusPhrase = ReadCountedString();
                } 
                else
                if (headerType == TcpHeaders.ContentType)
                {
                    ReadAndVerifyHeaderFormat("Content-Type", TcpHeaderFormat.CountedString); 

                    String contentType = ReadCountedString(); 
                    headers.ContentType = contentType; 
                }
                else 
                {
                    // unknown header: Read header format and ignore rest of data
                    byte headerFormat = (byte)ReadByte();
 
                    switch (headerFormat)
                    { 
                    case TcpHeaderFormat.Void: break; 
                    case TcpHeaderFormat.CountedString: ReadCountedString(); break;
                    case TcpHeaderFormat.Byte: ReadByte(); break; 
                    case TcpHeaderFormat.UInt16: ReadUInt16(); break;
                    case TcpHeaderFormat.Int32: ReadInt32(); break;

                    default: 
                    {
                        // unknown format 
                        throw new RemotingException( 
                            String.Format(
                                CultureInfo.CurrentCulture, CoreChannel.GetResourceString("Remoting_Tcp_UnknownHeaderType"), 
                                headerType, headerFormat));
                    }

                    } // switch (format) 

                } 
 
                // read next header token
                headerType = ReadUInt16(); 
            } // loop until end of headers

            // if an error occurred, throw an exception
            if (bError) 
            {
                if (statusPhrase == null) 
                    statusPhrase = ""; 

                throw new RemotingException( 
                    String.Format(
                        CultureInfo.CurrentCulture, CoreChannel.GetResourceString("Remoting_Tcp_GenericServerError"),
                        statusPhrase));
            } 
        } // ReadToEndOfHeaders
 
        private void ReadAndVerifyHeaderFormat(String headerName, byte expectedFormat) 
        {
            byte headerFormat = (byte)ReadByte(); 

            if (headerFormat != expectedFormat)
            {
                throw new RemotingException( 
                    String.Format(
                        CultureInfo.CurrentCulture, CoreChannel.GetResourceString("Remoting_Tcp_IncorrectHeaderFormat"), 
                        expectedFormat, headerName)); 
            }
        } // ReadAndVerifyHeaderFormat 

        // Prepare for reading a new request off of the same socket
        protected override void PrepareForNewMessage()
        { 
        } // PrepareForNewRequest
 
        protected override void SendErrorMessageIfPossible(Exception e) 
        {
            // bail out if the original request was OneWay (means the client doesn't even 
            //   want or expect to receive responses or error messages)
            if (_bOneWayRequest)
                return;
 
            // build up headers and send
            ChunkedMemoryStream headerStream = new ChunkedMemoryStream(CoreChannel.BufferPool); 
 
            // output preamble and version
            WritePreambleAndVersion(headerStream); 
            // output opcode
            WriteUInt16(TcpOperations.Reply, headerStream);
            // output content length delimiter (0-length stream)
            WriteUInt16(TcpContentDelimiter.ContentLength, headerStream); 
            WriteInt32(0, headerStream);
 
            // output status code and reason 
            WriteUInt16(TcpHeaders.StatusCode, headerStream);
            WriteByte(TcpHeaderFormat.UInt16, headerStream); 
            WriteUInt16(TcpStatusCode.GenericError, headerStream);
            // we purposely don't include the stack trace to avoid giving
            //   out too much information for security purposes.
            WriteUInt16(TcpHeaders.StatusPhrase, headerStream); 
            WriteByte(TcpHeaderFormat.CountedString, headerStream);
            WriteCountedString(e.ToString(), headerStream); 
 
            // indicate that we are about to close the connection
            WriteUInt16(TcpHeaders.CloseConnection, headerStream); 
            WriteByte(TcpHeaderFormat.Void, headerStream);

            // end of headers
            WriteUInt16(TcpHeaders.EndOfHeaders, headerStream); 

            headerStream.WriteTo(NetStream); 
            headerStream.Close(); 
        }
 
        internal void SendResponse(ITransportHeaders headers, Stream contentStream)
        {
            // bail out if the original request was OneWay (means the client doesn't even
            //   want or expect to receive responses or error messages) 
            if (_bOneWayRequest)
                return; 
 
            // build up headers and send
            ChunkedMemoryStream headerStream = new ChunkedMemoryStream(CoreChannel.BufferPool); 

            // output preamble and version
            WritePreambleAndVersion(headerStream);
            // output opcode 
            WriteUInt16(TcpOperations.Reply, headerStream);
            // output content length delimiter 
            WriteUInt16(TcpContentDelimiter.ContentLength, headerStream); 
            WriteInt32((int)contentStream.Length, headerStream);
 
            // No status code header is needed because if we're in this code path
            //   the data transfer succeeded as far as the transport protocol is
            //   concerned (and the success status code is optional).
 
            WriteHeaders(headers, headerStream);
 
            headerStream.WriteTo(NetStream); 
            headerStream.Close();
 
            StreamHelper.CopyStream(contentStream, NetStream);

            contentStream.Close();
        } 
    }
 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
//==========================================================================
//  File:       IpcHandler.cs 
//  Author:   [....]@Microsoft.com 
//  Summary:    Class for managing a socket connection.
// 
//=========================================================================

using System;
using System.IO; 
using System.Runtime.Remoting.Messaging;
using System.Runtime.InteropServices; 
using System.Text; 
using System.Threading;
using System.Runtime.Remoting.Channels.Tcp; 
using System.Globalization;


namespace System.Runtime.Remoting.Channels.Ipc 
{
 
    internal class IpcServerHandler : TcpSocketHandler 
    {
        // The stream to manage incoming request data 
        private Stream _stream = null;
        protected Stream _requestStream = null;
        // NamePipe associated with this manager
        protected IpcPort _port; 
        private RequestQueue _requestQueue;
        bool _bOneWayRequest; 
        int _contentLength; 

        internal IpcServerHandler(IpcPort port, RequestQueue requestQueue, Stream stream) : base (null, requestQueue, stream) 
        {
            _requestQueue = requestQueue;
            _port = port;
            _stream = stream; 
        }
 
        internal Stream GetRequestStream() 
        {
                _requestStream =  new TcpFixedLengthReadingStream(this, _contentLength); 
                return _requestStream;
        }

        internal IpcPort Port { 
            get {
                return _port; 
            } 
        }
 
        internal ITransportHeaders ReadHeaders()
        {
            BaseTransportHeaders headers = new BaseTransportHeaders();
 
            UInt16 operation;
            ReadVersionAndOperation(out operation); 
 
            if (operation == TcpOperations.OneWayRequest)
            { 
                _bOneWayRequest = true;
            }

            bool bChunked = false; 
            // content length must come next (may be chunked or a specific length)
            ReadContentLength(out bChunked, out _contentLength); 
 
            // read to end of headers
            ReadToEndOfHeaders(headers); 

            return headers;
        }
 
        protected new void ReadToEndOfHeaders(BaseTransportHeaders headers)
        { 
            bool bError = false; 
            String statusPhrase = null;
 
            UInt16 headerType = ReadUInt16();
            while (headerType != TcpHeaders.EndOfHeaders)
            {
                if (headerType == TcpHeaders.Custom) 
                {
                    String headerName = ReadCountedString(); 
                    String headerValue = ReadCountedString(); 

                    headers[headerName] = headerValue; 
                }
                else
                if (headerType == TcpHeaders.RequestUri)
                { 
                    ReadAndVerifyHeaderFormat("RequestUri", TcpHeaderFormat.CountedString);
 
                    // read uri (and make sure that no channel specific data is present) 
                    String uri = ReadCountedString();
 
                    String channelURI;
                    String objectURI;
                    channelURI = IpcChannelHelper.ParseURL(uri, out objectURI);
                    if (channelURI == null) 
                        objectURI = uri;
 
                    headers.RequestUri = objectURI; 
                }
                else 
                if (headerType == TcpHeaders.StatusCode)
                {
                    ReadAndVerifyHeaderFormat("StatusCode", TcpHeaderFormat.UInt16);
 
                    UInt16 statusCode = ReadUInt16();
                    // We'll throw an exception here if there was an error. If an error 
                    //   occurs above the transport level, the status code will still be 
                    //   success here.
                    if (statusCode != TcpStatusCode.Success) 
                        bError = true;
                }
                else
                if (headerType == TcpHeaders.StatusPhrase) 
                {
                    ReadAndVerifyHeaderFormat("StatusPhrase", TcpHeaderFormat.CountedString); 
 
                    statusPhrase = ReadCountedString();
                } 
                else
                if (headerType == TcpHeaders.ContentType)
                {
                    ReadAndVerifyHeaderFormat("Content-Type", TcpHeaderFormat.CountedString); 

                    String contentType = ReadCountedString(); 
                    headers.ContentType = contentType; 
                }
                else 
                {
                    // unknown header: Read header format and ignore rest of data
                    byte headerFormat = (byte)ReadByte();
 
                    switch (headerFormat)
                    { 
                    case TcpHeaderFormat.Void: break; 
                    case TcpHeaderFormat.CountedString: ReadCountedString(); break;
                    case TcpHeaderFormat.Byte: ReadByte(); break; 
                    case TcpHeaderFormat.UInt16: ReadUInt16(); break;
                    case TcpHeaderFormat.Int32: ReadInt32(); break;

                    default: 
                    {
                        // unknown format 
                        throw new RemotingException( 
                            String.Format(
                                CultureInfo.CurrentCulture, CoreChannel.GetResourceString("Remoting_Tcp_UnknownHeaderType"), 
                                headerType, headerFormat));
                    }

                    } // switch (format) 

                } 
 
                // read next header token
                headerType = ReadUInt16(); 
            } // loop until end of headers

            // if an error occurred, throw an exception
            if (bError) 
            {
                if (statusPhrase == null) 
                    statusPhrase = ""; 

                throw new RemotingException( 
                    String.Format(
                        CultureInfo.CurrentCulture, CoreChannel.GetResourceString("Remoting_Tcp_GenericServerError"),
                        statusPhrase));
            } 
        } // ReadToEndOfHeaders
 
        private void ReadAndVerifyHeaderFormat(String headerName, byte expectedFormat) 
        {
            byte headerFormat = (byte)ReadByte(); 

            if (headerFormat != expectedFormat)
            {
                throw new RemotingException( 
                    String.Format(
                        CultureInfo.CurrentCulture, CoreChannel.GetResourceString("Remoting_Tcp_IncorrectHeaderFormat"), 
                        expectedFormat, headerName)); 
            }
        } // ReadAndVerifyHeaderFormat 

        // Prepare for reading a new request off of the same socket
        protected override void PrepareForNewMessage()
        { 
        } // PrepareForNewRequest
 
        protected override void SendErrorMessageIfPossible(Exception e) 
        {
            // bail out if the original request was OneWay (means the client doesn't even 
            //   want or expect to receive responses or error messages)
            if (_bOneWayRequest)
                return;
 
            // build up headers and send
            ChunkedMemoryStream headerStream = new ChunkedMemoryStream(CoreChannel.BufferPool); 
 
            // output preamble and version
            WritePreambleAndVersion(headerStream); 
            // output opcode
            WriteUInt16(TcpOperations.Reply, headerStream);
            // output content length delimiter (0-length stream)
            WriteUInt16(TcpContentDelimiter.ContentLength, headerStream); 
            WriteInt32(0, headerStream);
 
            // output status code and reason 
            WriteUInt16(TcpHeaders.StatusCode, headerStream);
            WriteByte(TcpHeaderFormat.UInt16, headerStream); 
            WriteUInt16(TcpStatusCode.GenericError, headerStream);
            // we purposely don't include the stack trace to avoid giving
            //   out too much information for security purposes.
            WriteUInt16(TcpHeaders.StatusPhrase, headerStream); 
            WriteByte(TcpHeaderFormat.CountedString, headerStream);
            WriteCountedString(e.ToString(), headerStream); 
 
            // indicate that we are about to close the connection
            WriteUInt16(TcpHeaders.CloseConnection, headerStream); 
            WriteByte(TcpHeaderFormat.Void, headerStream);

            // end of headers
            WriteUInt16(TcpHeaders.EndOfHeaders, headerStream); 

            headerStream.WriteTo(NetStream); 
            headerStream.Close(); 
        }
 
        internal void SendResponse(ITransportHeaders headers, Stream contentStream)
        {
            // bail out if the original request was OneWay (means the client doesn't even
            //   want or expect to receive responses or error messages) 
            if (_bOneWayRequest)
                return; 
 
            // build up headers and send
            ChunkedMemoryStream headerStream = new ChunkedMemoryStream(CoreChannel.BufferPool); 

            // output preamble and version
            WritePreambleAndVersion(headerStream);
            // output opcode 
            WriteUInt16(TcpOperations.Reply, headerStream);
            // output content length delimiter 
            WriteUInt16(TcpContentDelimiter.ContentLength, headerStream); 
            WriteInt32((int)contentStream.Length, headerStream);
 
            // No status code header is needed because if we're in this code path
            //   the data transfer succeeded as far as the transport protocol is
            //   concerned (and the success status code is optional).
 
            WriteHeaders(headers, headerStream);
 
            headerStream.WriteTo(NetStream); 
            headerStream.Close();
 
            StreamHelper.CopyStream(contentStream, NetStream);

            contentStream.Close();
        } 
    }
 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
